package snakegame.versionfromcsdn.src;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

public class GamePanel extends JPanel implements KeyListener, ActionListener {//集成画板类，实现键盘监听方法

    public GamePanel() {
        init();
        this.setFocusable(true);//让这个组件获取到焦点
        this.addKeyListener(this);
        /*
       用于接收键盘事件（击键）的侦听器接口。
                使用组件的 addKeyListener 方法将从该类所创建的侦听器对象向该组件注册。按下、释放或键入键时生成键盘事件。
            然后调用侦听器对象中的相关方法并将该 KeyEvent 传递给它。
         */
        timer.start();//计时器打开
    }

    Timer timer = new Timer(160, this);//每160毫秒刷新一次，保证动画动起来
    int lenth;
    int foodx = 0;//设置食物的横坐标
    int foody = 0;//设置食物的纵坐标
    boolean isfood = false;//设置当前是否有食物变量，默认为假
    boolean start = false;//设置当前游戏是否开始变量，默认为假
    boolean iskilled=false;
    String fx = "R";//R 向右 L向左 U向上 D向下
    int[] snakex = new int[999];
    int[] snakey = new int[999];
    Random Ran = new Random();//创建随机数对象，给食物的坐标生成随机数并且赋值

    public void init() {//初始化方法，当本类被构造的时候被执行一次
        fx = "R";
        lenth = 9;//设置蛇的输出长度
        snakex[0] = 200;
        snakey[0] = 100;//头部坐标
        snakex[1] = 200;
        snakey[1] = 100;
        snakex[2] = 179;
        snakey[2] = 100;//第一节坐标
        for (int i = 2; i < lenth; i++) {
            /*
            其他节坐标以此赋值，因为第一节身体坐标与头部一样，
            所以从第二节开始输出
             */
            snakex[i + 1] = snakex[i] - 19;
            snakey[i + 1] = snakey[i];
        }
    }

    @Override
    protected void paintComponent(Graphics g) {//重写这个方法
        super.paintComponent(g);//清屏的作用，Graphics g 画笔
        this.setBackground(Color.lightGray);//设置画板背景颜色
        g.fillRect(0, 0, 884, 681);//添加组件，绘制游戏区域
        if (fx.equals("R"))//判断方向是哪个，输出对应的方向图标
            data.right.paintIcon(this, g, snakex[0], snakey[0]);
        else if (fx.equals("L"))
            data.left.paintIcon(this, g, snakex[0], snakey[0]);
        else if (fx.equals("U"))
            data.up.paintIcon(this, g, snakex[0], snakey[0]);
        else if (fx.equals("D"))
            data.down.paintIcon(this, g, snakex[0], snakey[0]);
        for (int i = 2; i < lenth; i++) {//循环输出多少个身体
            data.body.paintIcon(this, g, snakex[i], snakey[i]);
        }
        data.food.paintIcon(this, g, foodx, foody);//输出食物
        g.setColor(Color.WHITE);//设置画笔的颜色
        g.setFont(new Font("宋体", Font.BOLD, 20));//设置画笔的大小，字体，
        g.drawString("当前得分：" + (lenth - 9), 750, 50);//画笔输出对应的分数
        if (start == false) {//游戏是否开始，如果没有开始利用画笔在画板内写一句话
            g.setFont(new Font("宋体", Font.BOLD, 40));
            g.drawString("按下空格键进行游戏！", 250, 300);
        }
        /*
        用循环不断检查蛇头坐标与身体坐标是否相等，如果相等，定时器终止，则提示游戏结束
         */
        for (int i = 3; i < lenth; i++) {
            if (snakey[0] == snakey[i] && snakex[0] == snakex[i]) {
                System.out.println("游戏结束！");
                timer.stop();//游戏画面暂停
                iskilled=true;//死亡 状态变为真
                g.setFont(new Font("宋体", Font.BOLD, 40));
                g.drawString("游戏结束！按空格键重新开始游戏", 120, 300);
            }
        }

    }

    @Override
    public void keyPressed(KeyEvent e) {//键盘按下，未释放操作
        int keycode = e.getKeyCode();//定义一个变量用来接收键盘的数据
        if (keycode == 32)  //如果按下空格键(数字32)，用来启动或者暂停
        {
            if (iskilled==true){//如果死亡状态为真，初始化全部参数，进行下一次游戏
                init();
                timer.start();
            }
            iskilled=false;
            start = !start;
            repaint();//刷新界面
        }
        /*
        为了防止向左运动的时候，方向键给予一个向右的命令造成死亡，所以设置了在向一个方向运动的时候，
        相反方向的命令不能够被运行。
        方法是当键盘接收到一个方向指令以后，判断是不是当前方向与获取的指令是否相反，相反则不允许更改
        当前方向
         */
        else if (keycode == 38 && fx != "D") {
            fx = "U";
        } else if (keycode == 40 && fx != "U") {
            fx = "D";
        } else if (keycode == 37 && fx != "R") {
            fx = "L";
        } else if (keycode == 39 && fx != "L") {
            fx = "R";
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {//执行定时操作
        if (start == true) {//游戏开始以后，让小蛇动起来
            if (fx.equals("R")) {
                if (snakex[0] > 884) {//超出边界就把坐标变成初始值
                    snakex[0] = 19;
                }
                snakex[0] = snakex[0] + 20;
                for (int i = lenth - 1; i > 0; i--) {//输出右移时候的身子
                    snakex[i] = snakex[i - 1];
                    snakey[i] = snakey[i - 1];
                }
            } else if (fx.equals("L")) {
                if (snakex[0] < 0) {
                    snakex[0] = 885;
                }
                snakex[0] = snakex[0] - 20;

                for (int i = lenth - 1; i > 0; i--) {//输出左移时候的身子
                    snakex[i] = snakex[i - 1];
                    snakey[i] = snakey[i - 1];
                }
            } else if (fx.equals("U")) {
                snakey[0] = snakey[0] - 20;

                if (snakey[0] <10) {
                    snakey[0] = 680;
                }
                for (int i = lenth - 1; i > 0; i--) {//输出上移时候的身子
                    snakex[i] = snakex[i - 1];
                    snakey[i] = snakey[i - 1];
                }
            } else if (fx.equals("D")) {
                snakey[0] = snakey[0] + 20;//每次行走的单位
                if (snakey[0] > 685) {//判断边界值
                    snakey[0] = 1;
                }
                for (int i = lenth - 1; i > 0; i--) {//输出下移时候的身子
                    snakex[i] = snakex[i - 1];
                    snakey[i] = snakey[i - 1];
                }
            }

        }
        if (!isfood) {//判断地图是否存在食物，如果没有，就会进行一次绘图，把食物绘图在地图上
//                      食物的坐标通过Random置随机种子完成

            foodx = Ran.nextInt(600);
            foody = Ran.nextInt(600);
            System.out.println(foodx);//输出食物的横坐标
            System.out.println(foody);//输出食物的纵坐标
            isfood = !isfood;
        }
           /*
        判断食物是否被吃,因为蛇的单位是每20个单位进行行走，如果判断头的坐标和食物坐标完全相等时不现实的，所以就利用蛇与食物的
        绝对值相差19（蛇每走一步是20单位）以下认为吃到了食物！
        也可以在1-20置随机数，得到的随机数乘以20，保证是20的倍数，这样就存在与小蛇坐标相等的情况
         */
        if (Math.abs(snakex[0] - foodx) < 19 && Math.abs(snakey[0] - foody) < 19) {
            isfood = !isfood;//把状态取反
            lenth++;//蛇的长度自加
        }
        repaint();//清屏
        timer.start();//定时器开始

    }
    /*
    一下两个重写方法对于本项目没有太的用处，所以不再赘述
     */

    @Override
    public void keyReleased(KeyEvent e) {//释放某个键操作

    }

    @Override
    public void keyTyped(KeyEvent e) {//键盘按下弹起操作
    }
}
